package org.linlinjava.litemall.admin.exception;

import org.apache.http.util.TextUtils;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.linlinjava.litemall.core.config.BizException;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.List;
import java.util.Set;

/**
 * @author wj
 * @date 2021/9/1 14:56
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);



    /**
     * 获取报错的堆栈信息
     * @return
     */
    private static void generateTag(Throwable throwable) {
        StringWriter stringWriter=new StringWriter();
        PrintWriter printWriter=new PrintWriter(stringWriter);

        try {
            throwable.printStackTrace(printWriter);
            logger.error("错误日志:{}",stringWriter);
        }finally {
            printWriter.close();
        }
    }


    @ExceptionHandler(value = ConstraintViolationException.class)
    public Object handle(ConstraintViolationException ex){
        StringBuilder msg = new StringBuilder();
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        for (ConstraintViolation<?> constraintViolation : constraintViolations) {
            PathImpl pathImpl = (PathImpl) constraintViolation.getPropertyPath();
            String paramName = pathImpl.getLeafNode().getName();
            String message = constraintViolation.getMessage();
            msg.append("[").append(message).append("]");
        }
        // 注意：Response类必须有get和set方法，不然会报错
        return ResponseUtil.fail(505,msg.toString());
    }


    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Object handle(MethodArgumentNotValidException ex){
        StringBuilder msg = new StringBuilder();
        List<ObjectError> allErrors = ex.getBindingResult().getAllErrors();
        if(allErrors.size()>0){
            for (int i = 0; i < allErrors.size(); i++) {
                msg.append(allErrors.get(i).getDefaultMessage()+"     ");
            }
            return ResponseUtil.fail(505,msg.toString());
        }
        else{
            return ResponseUtil.fail(505,"未知参数异常");
        }

    }


    @ExceptionHandler(value = BindException.class)
    public Object handle(BindException ex){
        StringBuilder msg = new StringBuilder();
        List<ObjectError> allErrors = ex.getBindingResult().getAllErrors();
        if(allErrors.size()>0){
            for (int i = 0; i < allErrors.size(); i++) {
                msg.append(allErrors.get(i).getDefaultMessage()+"     ");
            }
            return ResponseUtil.fail(505,msg.toString());
        }
        else{
            return ResponseUtil.fail(505,"未知参数异常");
        }
    }

    @ExceptionHandler(value = NullPointerException.class)
    public Object handle(NullPointerException ex){
        logger.error("506异常：{}",ex.getMessage());
        generateTag(ex);
            return ResponseUtil.fail(506,"参数/逻辑异常-空指针异常");
    }

    @ExceptionHandler(value = SQLIntegrityConstraintViolationException.class)
    public Object handle(SQLIntegrityConstraintViolationException ex){
        logger.error("600异常：{}",ex.toString());
        generateTag(ex);
            return ResponseUtil.fail(600,"数据库操作异常");
    }


    @ExceptionHandler(value = NumberFormatException.class)
    public Object handle(NumberFormatException ex){
        logger.error("601异常：{}",ex.toString());
        generateTag(ex);
            return ResponseUtil.fail(601,"基本类型转换异常");
    }
//
//    @ExceptionHandler(value = RuntimeException.class)
//    public Object handle(RuntimeException ex){
//        logger.error(ex.toString());
//        return ResponseUtil.fail(500,"未知异常");
//    }
//
//    @ExceptionHandler(value = Exception.class)
//    public Object handle(Exception ex){
//        logger.error(ex.toString());
//        return ResponseUtil.fail(500,"未知异常");
//    }

    @ExceptionHandler(BizException.class)
    @ResponseBody
    public Object bieExcrptionHandler(BizException e) {
        logger.error(e.getMessage(), e);
        return ResponseUtil.fail(502, e.getMessage());
    }

}
